<?php
/**
 * 文件下载类
 */
class download {
	/**
	 * 路径,文件名,全称
	 */
	private $data = null;
	private $data_len = 0;
	private $data_modify = 0;
	/**
	 * 0 file ; 1 data;2 url Header(Location:***)
	 */
	private $data_type = 0;
	private $data_section = 0;
	
	/**
	 * Object Handler
	 */
	// 考滤是否删除此功能
	
	/**
	 * 是否可以断点下载
	 */
	public $use_resume = true;
	public $filename = null;
	public $mime = 'application/octet-stream';
	
	/**
	 * 每个content 的大小
	 */
	public $bufsize = 2048;
	private $seek_start = 0;
	private $seeek_end = - 1;
	/**
	 * Total bandwidth has been used for this download
	 * @var int
	 */
	var $bandwidth = 0;
	/**
	 * Speed limit
	 * @var float
	 */
	var $speed = 0;
	/**
	 * 析构函数
	 */
	function __construct() {
			
			// Update $seek_start $seek_end
		if (isset ( $_SERVER ['HTTP_RANGE'] )) {
			
		$seek_range = substr ( $_SERVER ['HTTP_RANGE'], strlen ( 'bytes=' ) );
			
			$range = explode ( '-', $seek_range );
			
			if ($range [0] > 0) {
				$this->seek_start = intval ( $range [0] );
			}
			
			if ($range [1] > 0)
				$this->seek_end = intval ( $range [1] );
			else
				$this->seek_end = - 1;
			
			if (! $this->use_resume) {
				$this->seek_start = 0;
				
				// header("HTTP/1.0 404 Bad Request");
				// header("Status: 400 Bad Request");
				
				// exit;
				
				// return false;
			} else {
				$this->data_section = 1;
			}
		} else {
			$this->seek_start = 0;
			$this->seek_end = - 1;
		}
	}
	
	/**
	 * Send download information header
	 **/
	function header($size,$seek_start=null,$seek_end=null) {
		header('Content-type: ' . $this->mime);
		header('Content-Disposition: attachment; filename="' . $this->filename . '"');
		header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T' , $this->data_modify));
	
		if ($this->data_section && $this->use_resume)
		{
			header("HTTP/1.0 206 Partial Content");
			header("Status: 206 Partial Content");
			header('Accept-Ranges: bytes');
			header("Content-Range: bytes $seek_start-$seek_end/$size");
			header("Content-Length: " . ($seek_end - $seek_start + 1));
		}
		else
		{
			header("Content-Length: $size");
		}
	}
	
	/**
	 * Start download
	 * @return bool
	 **/
	function download() {
	
		$seek = $this->seek_start;
		$speed = $this->speed;
		$bufsize = $this->bufsize;
		$packet = 1;
	
		//do some clean up
		@ob_end_clean();
		$old_status = ignore_user_abort(true);
		@set_time_limit(0);
		$this->bandwidth = 0;
	
		$size = $this->data_len;
	//switch start
		switch ($this->data_type){
			//////////////**************download from a file*****************///////////////////////
			case 0:
				$size = filesize($this->data);
				if ($seek > ($size - 1)) $seek = 0;
				if ($this->filename == null) $this->filename = basename($this->data);
				
				$res = fopen($this->data,'rb');
				if ($seek) fseek($res , $seek);
				if ($this->seek_end < $seek) $this->seek_end = $size - 1;
				
				$this->header($size,$seek,$this->seek_end); //always use the last seek
				$size = $this->seek_end - $seek + 1;
				
				while (!(connection_aborted() || connection_status() == 1) && $size > 0)
				{
					if ($size < $bufsize)
					{
						echo fread($res , $size);
						$this->bandwidth += $size;
					}
					else
					{
						echo fread($res , $bufsize);
						$this->bandwidth += $bufsize;
					}
				
					$size -= $bufsize;
					flush();
				
					if ($speed > 0 && ($this->bandwidth > $speed*$packet*1024))
					{
						sleep(1);
						$packet++;
					}
				}
				fclose($res);
				break;
				////////////******************download from a string****************////////////////////
			case 1:	
				if ($seek > ($size - 1)) $seek = 0;
				if ($this->seek_end < $seek) $this->seek_end = $this->data_len - 1;
				$this->data = substr($this->data , $seek , $this->seek_end - $seek + 1);
				if ($this->filename == null) $this->filename = time();
				$size = strlen($this->data);
				$this->header($this->data_len,$seek,$this->seek_end);
				while (!connection_aborted() && $size > 0) {
					if ($size < $bufsize)
					{
						$this->bandwidth += $size;
					}
					else
					{
						$this->bandwidth += $bufsize;
					}
				
					echo substr($this->data , 0 , $bufsize);
					$this->data = substr($this->data , $bufsize);
				
					$size -= $bufsize;
					flush();
				
					if ($speed > 0 && ($this->bandwidth > $speed*$packet*1024))
					{
						sleep(1);
						$packet++;
					}
				}
				break;
			/////////////****************just send a redirect header******************//////////
			case 2:	
				header('location: ' . $this->data);
				break;
		}//end switch
	
		//restore old status
		ignore_user_abort($old_status);
		set_time_limit(ini_get("max_execution_time"));
	
		return true;
	}
	
	function set_byfile($dir) {
		if (is_readable($dir) && is_file($dir)) {
			$this->data_len = 0;
			$this->data = $dir;
			$this->data_type = 0;
			$this->data_modify = filemtime($dir);
			return true;
		} else return false;
	}
	
	function set_bydata($data) {
		if ($data == '') return false;
		$this->data = $data;
		$this->data_len = strlen($data);
		$this->data_type = 1;
		$this->data_modify = time();
		return true;
	}
	
	function set_byurl($data) {
		$this->data = $data;
		$this->data_len = 0;
		$this->data_type = 2;
		return true;
	}
	
	function set_lastmodtime($time) {
		$time = intval($time);
		if ($time <= 0) $time = time();
		$this->data_modify = $time;
	}
}